package com.xxljob.demo;

import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.util.FileUtil;
import com.xxl.job.core.util.JdkSerializeTool;
import com.xxljob.demo.core.conf.XxlJobAdminConfig;
import com.xxljob.demo.core.model.XxlJobInfo;
import com.xxljob.demo.core.thread.JobTriggerPoolHelper;
import com.xxljob.demo.core.trigger.TriggerTypeEnum;
import com.xxljob.demo.dao.XxlJobInfoDao;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@SpringBootTest
class TriggerCallbackThread {

    private static final Logger logger = LoggerFactory.getLogger(DemoApplication.class);

    static class InvokeObj {
        public void show() {
            logger.info("无参show()方法。");
        }

        public void show(String name) {
            logger.info("有参数show方法: {}", name);
        }

        public void show(String a, String b) {
            logger.info("两个参数show方法:{}, {}", a, b);
        }

        public String[] arrayShow(String[] arr) {
            return arr;
        }

        public String StringShow(String str) {
            return str;
        }

        public int intShow(int num) {
            return num;
        }
    }

    @Test
    public void reflect() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Class<InvokeObj> clazz = InvokeObj.class;
        Method[] methods = clazz.getMethods();

        Method show = clazz.getMethod("show", null);
        show.invoke(new InvokeObj(), null);

        Method show1 = clazz.getMethod("show", String.class);
        show1.invoke(new InvokeObj(), "测试数据");

        Method show2 = clazz.getMethod("show", String.class, String.class);
        show2.invoke(new InvokeObj(), "测试数据1", "测试数据2");
    }

    private static final long PRE_READ_MS = 5000;

    private static final int preReadCount = 6000;

    private static String failCallbackFilePath;

    private static String failCallbackFileName;

    public TriggerCallbackThread() {
    }


    public static TriggerCallbackThread getInstance() {
        return instance;
    }

    private static TriggerCallbackThread instance = new TriggerCallbackThread();
    private LinkedBlockingQueue<HandleCallbackParam> callBackQueue = new LinkedBlockingQueue();
    private Thread triggerCallbackThread;
    private Thread triggerRetryCallbackThread;
    private volatile boolean toStop = false;


    @Resource
    private XxlJobInfoDao xxlJobInfoDao;

    @Test
    void startTest() {
        multiThread();
    }

    public void multiThread() {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,
                20,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(200),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "xxl-thread-" + r.hashCode());
                    }
                });
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("线程池异步线程运行" + Thread.currentThread().getName());

            }
        });
        logger.info("主线程运行" + Thread.currentThread().getName());
    }


    public void start() {
        if (XxlJobExecutor.getAdminBizList() != null) {
            logger.warn(">>>>>>>>>>> xxl-job, executor callback config fail, adminAddresses is null.");
        } else {
            this.triggerCallbackThread = new Thread(new Runnable() {
                public void run() {
                    while (!TriggerCallbackThread.this.toStop) {
                        try {
                            logger.info("triggerCallbackThread运行");
                            HandleCallbackParam callback =
                                    (HandleCallbackParam) TriggerCallbackThread.getInstance().callBackQueue.take();
                            if (callback != null) {
                                List<HandleCallbackParam> callbackParamListx = new ArrayList();
                                int drainToNumx =
                                        TriggerCallbackThread.getInstance().callBackQueue.drainTo(callbackParamListx);
                                callbackParamListx.add(callback);
                                if (callbackParamListx != null && callbackParamListx.size() > 0) {
                                    TriggerCallbackThread.this.doCallback(callbackParamListx);
                                }
                            }
                        } catch (Exception var4) {
                            if (!TriggerCallbackThread.this.toStop) {
                                TriggerCallbackThread.logger.error(var4.getMessage(), var4);
                            }
                        }
                    }
                    logger.info("运行到下面了");

                    try {
                        List<HandleCallbackParam> callbackParamList = new ArrayList();
                        int drainToNum = TriggerCallbackThread.getInstance().callBackQueue.drainTo(callbackParamList);
                        if (callbackParamList != null && callbackParamList.size() > 0) {
                            TriggerCallbackThread.this.doCallback(callbackParamList);
                        }
                    } catch (Exception var5) {
                        if (!TriggerCallbackThread.this.toStop) {
                            logger.error(var5.getMessage(), var5);
                        }
                    }
                    logger.info(">>>>>>>>>>> xxl-job, executor callback" +
                            " thread destory.");
                }
            });
            this.triggerCallbackThread.setDaemon(true);
            this.triggerCallbackThread.setName("triggerCallbackThread");
            this.triggerCallbackThread.start();


            this.triggerRetryCallbackThread = new Thread(new Runnable() {
                public void run() {
                    while (!TriggerCallbackThread.this.toStop) {
                        try {
                            TriggerCallbackThread.this.retryFailCallbackFile();
                        } catch (Exception var3) {
                            if (!TriggerCallbackThread.this.toStop) {
                                TriggerCallbackThread.logger.error(var3.getMessage(), var3);
                            }
                        }

                        try {
                            TimeUnit.SECONDS.sleep(30L);
                        } catch (InterruptedException var2) {
                            if (!TriggerCallbackThread.this.toStop) {
                                TriggerCallbackThread.logger.error(var2.getMessage(), var2);
                            }
                        }
                    }

                    logger.info(">>>>>>>>>>> xxl-job, executor retry callback thread destory.");
                }
            });
            this.triggerRetryCallbackThread.setDaemon(true);
            this.triggerRetryCallbackThread.setName("triggerRetryCallbackThread");
            //this.triggerRetryCallbackThread.start();
        }
    }

    private void retryFailCallbackFile() {
        File callbackLogPath = new File(failCallbackFilePath);
        if (callbackLogPath.exists()) {
            if (callbackLogPath.isFile()) {
                callbackLogPath.delete();
            }

            if (callbackLogPath.isDirectory() && callbackLogPath.list() != null && callbackLogPath.list().length > 0) {
                File[] var2 = callbackLogPath.listFiles();
                int var3 = var2.length;

                for (int var4 = 0; var4 < var3; ++var4) {
                    File callbaclLogFile = var2[var4];
                    byte[] callbackParamList_bytes = FileUtil.readFileContent(callbaclLogFile);
                    List<HandleCallbackParam> callbackParamList =
                            (List) JdkSerializeTool.deserialize(callbackParamList_bytes, List.class);
                    callbaclLogFile.delete();
                    this.doCallback(callbackParamList);
                }

            }
        }
    }

    @Test
    public void dateTest() {
        long nowTime = System.currentTimeMillis();
        List<XxlJobInfo> scheduleList =
                XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleJobQuery(nowTime + PRE_READ_MS,
                        preReadCount);
        if (Objects.nonNull(scheduleList) && scheduleList.size() > 0) {
            // 2、push time-ring
            for (XxlJobInfo info : scheduleList) {
                JobTriggerPoolHelper.trigger(info.getId(), TriggerTypeEnum.CRON, -1, null, null,
                        null);
            }
        }
    }

    private void doCallback(List<HandleCallbackParam> callbackParamList) {
        boolean callbackRet = false;
        Iterator var3 = XxlJobExecutor.getAdminBizList().iterator();

        while (var3.hasNext()) {
            AdminBiz adminBiz = (AdminBiz) var3.next();

            try {
                ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);
                if (callbackResult != null && 200 == callbackResult.getCode()) {
                    this.callbackLog(callbackParamList, "<br>----------- xxl-job job callback finish.");
                    callbackRet = true;
                    break;
                }

                this.callbackLog(callbackParamList,
                        "<br>----------- xxl-job job callback fail, callbackResult:" + callbackResult);
            } catch (Exception var6) {
                this.callbackLog(callbackParamList,
                        "<br>----------- xxl-job job callback error, errorMsg:" + var6.getMessage());
            }
        }

        if (!callbackRet) {
//            this.appendFailCallbackFile(callbackParamList);
        }
    }

    private void callbackLog(List<HandleCallbackParam> callbackParamList, String logContent) {
        Iterator var3 = callbackParamList.iterator();

        while (var3.hasNext()) {
            HandleCallbackParam callbackParam = (HandleCallbackParam) var3.next();
            String logFileName = XxlJobFileAppender.makeLogFileName(new Date(callbackParam.getLogDateTim()),
                    callbackParam.getLogId());
            XxlJobFileAppender.contextHolder.set(logFileName);
            XxlJobLogger.log(logContent, new Object[0]);
        }
    }

    @Test
    public void get() {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            // 创建httpget.
            HttpGet httpget = new HttpGet("http://www.baidu.com/");
            System.out.println("executing request " + httpget.getURI());
            // 执行get请求.
            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                // 获取响应实体
                final HttpEntity entity = response.getEntity();
                System.out.println("--------------------------------------");
                // 打印响应状态
                System.out.println(response.getStatusLine());
                if (entity != null) {
                    // 打印响应内容长度
                    System.out.println("Response content length: " + entity.getContentLength());
                    // 打印响应内容
                    System.out.println("Response content: " + EntityUtils.toString(entity));
                }
                System.out.println("------------------------------------");
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接,释放资源
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
